//////////////////////////////////////////////////////////////////////////
#include "Ml.Enums.h"
//////////////////////////////////////////////////////////////////////////
#pragma once
#pragma managed
//////////////////////////////////////////////////////////////////////////
NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////
public value struct Vectors
{
	int type;
	int dims;
	int count;
	IntPtr next;
	IntPtr data;
};

public value struct ParamGrid
{
	ParamGrid(double _min_val, double _max_val, double log_step)
	{
		min_val = _min_val;
		max_val = _max_val;
		step = log_step;
	}

	bool check()
	{
		CvParamGrid grid(min_val, max_val, step);
		return grid.check();
	}

	double min_val;
	double max_val;
	double step;
};

// SVM training parameters
public value struct SVMParams
{
	SVMParams(
		SVMType _svm_type, 
		SVMKernelType _kernel_type, 
		double _degree, 
		double _gamma, 
		double _coef0,
		double _C, 
		double _nu, 
		double _p,
		IntPtr _class_weights, 
		TermCriteria _term_crit)
	{
		svm_type = _svm_type;
		kernel_type = _kernel_type;
		degree = _degree;
		gamma = _gamma;
		coef0 = _coef0;
		C = _C;
		nu = _nu;
		p = _p;
		class_weights = _class_weights;
		term_crit = _term_crit;
	}

	SVMType         svm_type;
	SVMKernelType         kernel_type;
	double      degree; // for poly
	double      gamma;  // for poly/rbf/sigmoid
	double      coef0;  // for poly/sigmoid

	double      C;  // for CV_SVM_C_SVC, CV_SVM_EPS_SVR and CV_SVM_NU_SVR
	double      nu; // for CV_SVM_NU_SVC, CV_SVM_ONE_CLASS, and CV_SVM_NU_SVR
	double      p; // for CV_SVM_EPS_SVR
	IntPtr      class_weights; // for CV_SVM_C_SVC
	TermCriteria term_crit; // termination criteria

	/// Default property
	static property SVMParams Default
	{
		SVMParams get()
		{
			SVMParams params;
			return params;
		}
	}
};

public value struct EMParams
{
	int nclusters;
	EMCovMatType cov_mat_type;
	EMInitialStep start_step;
	IntPtr probs;
	IntPtr weights;
	IntPtr means;
	IntPtr covs;
	TermCriteria term_crit;

	EMParams(int _nclusters, 
		EMCovMatType _cov_mat_type,
		EMInitialStep _start_step,
		TermCriteria _term_crit,
		IntPtr _probs,
		IntPtr _weights,
		IntPtr _means,
		IntPtr _covs) 
	{
		nclusters = _nclusters; 
		cov_mat_type = _cov_mat_type; 
		start_step = _start_step;
		probs = _probs; 
		weights = _weights; 
		means = _means; 
		covs = _covs; 
		term_crit = _term_crit;
	}

	EMParams(int _nclusters, 
		EMCovMatType _cov_mat_type,
		EMInitialStep _start_step,
		TermCriteria _term_crit,
		IntPtr _probs,
		IntPtr _weights,
		IntPtr _means) 
	{
		nclusters = _nclusters; 
		cov_mat_type = _cov_mat_type; 
		start_step = _start_step;
		probs = _probs; 
		weights = _weights; 
		means = _means; 
		term_crit = _term_crit;
	}

	EMParams(int _nclusters, 
		EMCovMatType _cov_mat_type,
		EMInitialStep _start_step,
		TermCriteria _term_crit,
		IntPtr _probs,
		IntPtr _weights) 
	{
		nclusters = _nclusters; 
		cov_mat_type = _cov_mat_type; 
		start_step = _start_step;
		probs = _probs; 
		weights = _weights; 
		term_crit = _term_crit;
	}

	EMParams(int _nclusters, 
		EMCovMatType _cov_mat_type,
		EMInitialStep _start_step,
		TermCriteria _term_crit,
		IntPtr _probs) 
	{
		nclusters = _nclusters; 
		cov_mat_type = _cov_mat_type; 
		start_step = _start_step;
		probs = _probs; 
		term_crit = _term_crit;
	}

	EMParams(int _nclusters, 
		EMCovMatType _cov_mat_type,
		EMInitialStep _start_step,
		TermCriteria _term_crit) 
	{
		nclusters = _nclusters; 
		cov_mat_type = _cov_mat_type; 
		start_step = _start_step;
		term_crit = _term_crit;
	}

	EMParams(int _nclusters, 
		EMCovMatType _cov_mat_type,
		EMInitialStep _start_step) 
	{
		nclusters = _nclusters; 
		cov_mat_type = _cov_mat_type; 
		start_step = _start_step;
	}

	EMParams(int _nclusters, 
		EMCovMatType _cov_mat_type) 
	{
		nclusters = _nclusters; 
		cov_mat_type = _cov_mat_type; 
	}

	EMParams(int _nclusters) 
	{
		nclusters = _nclusters; 
	}
};

[StructLayoutAttribute(LayoutKind::Explicit)]
public value struct DTreeSplit
{
	[FieldOffsetAttribute(0)]
	int var_idx;
	[FieldOffsetAttribute(4)]
	int condensed_idx;
	[FieldOffsetAttribute(8)]
	int inversed;
	[FieldOffsetAttribute(12)]
	float quality;
	[FieldOffsetAttribute(16)]
	IntPtr next;
	[FieldOffsetAttribute(20)]
	inline_array<int, 2> subset;

	value struct DTreeSplitOrd
	{
		float c;
		int split_point;
	};

	[FieldOffsetAttribute(20)]
	DTreeSplitOrd ord;
};


public value struct DTreeNode
{
	int class_idx;
	int Tn;
	double value;

	IntPtr parent;
	IntPtr left;
	IntPtr right;

	IntPtr split;

	int sample_count;
	int depth;
	IntPtr num_valid;
	int offset;
	int buf_idx;
	double maxlr;

	// global pruning data
	int complexity;
	double alpha;
	double node_risk, tree_risk, tree_error;

	// cross-validation pruning data
	IntPtr cv_Tn;
	IntPtr cv_node_risk;
	IntPtr cv_node_error;

	int get_num_valid(int vi) 
	{
		return num_valid != IntPtr::Zero ? ((int*)num_valid.ToPointer())[vi] : sample_count; 
	}

	void set_num_valid(int vi, int n) 
	{
		if (num_valid != IntPtr::Zero)
		{
			((int*)num_valid.ToPointer())[vi] = n; 
		}
	}
};

public value struct DTreeParams
{
	int   max_categories;
	int   max_depth;
	int   min_sample_count;
	int   cv_folds;
	bool  use_surrogates;
	bool  use_1se_rule;
	bool  truncate_pruned_tree;
	float regression_accuracy;
	IntPtr priors;

	DTreeParams( int _max_depth, int _min_sample_count,
		float _regression_accuracy, bool _use_surrogates,
		int _max_categories, int _cv_folds,
		bool _use_1se_rule, bool _truncate_pruned_tree,
		IntPtr _priors )
	{
		max_categories = _max_categories; 
		max_depth = _max_depth;
		min_sample_count = _min_sample_count; 
		cv_folds  = _cv_folds;
		use_surrogates = _use_surrogates; 
		use_1se_rule = _use_1se_rule;
		truncate_pruned_tree = _truncate_pruned_tree;
		regression_accuracy = _regression_accuracy;
		priors = _priors;
	}

	static property DTreeParams Default
	{
		DTreeParams get()
		{
			DTreeParams defaultParams = *(DTreeParams*)&(CvDTreeParams());
			return defaultParams;
		}
	}
};

public value struct RTParams
{
	DTreeParams dtree_params;
	//Parameters for the forest
	bool calc_var_importance; // true <=> RF processes variable importance
	int nactive_vars;
	TermCriteria term_crit;

	RTParams(int _max_depth, int _min_sample_count,
		float _regression_accuracy, bool _use_surrogates,
		int _max_categories, const float* _priors, bool _calc_var_importance,
		int _nactive_vars, int max_num_of_trees_in_the_forest,
		float forest_accuracy, TermCriteriaType termcrit_type)
	{
		*this = *(RTParams*)&(CvRTParams(
			_max_depth,
			_min_sample_count,
			_regression_accuracy,
			_use_surrogates,
			_max_categories, 
			_priors,
			_calc_var_importance,
			_nactive_vars,
			max_num_of_trees_in_the_forest,			
			forest_accuracy,
			(int)termcrit_type));
	}

	static property RTParams Default
	{
		RTParams get()
		{
			RTParams defaultParams = *(RTParams*)&(CvRTParams());
			return defaultParams;
		}
	}
};

public value struct BoostParams
{
	DTreeParams dtree_params;
	int boost_type;
	int weak_count;
	int split_criteria;
	double weight_trim_rate;
	BoostParams(int boost_type, int weak_count, double weight_trim_rate,
		int max_depth, bool use_surrogates, IntPtr priors)
	{
		*this = *(BoostParams*)&(CvBoostParams(boost_type, weak_count, weight_trim_rate, max_depth, use_surrogates, (float*)priors.ToPointer()));
	}

	static property BoostParams Default
	{
		BoostParams get()
		{
			BoostParams defaultParams = *(BoostParams*)&(CvBoostParams());
			return defaultParams;
		}
	}
};

public value struct ANNMLPTrainParams
{
	TermCriteria term_crit;
	ANNTrainMethod train_method;

	// backpropagation parameters
	double bp_dw_scale, bp_moment_scale;

	// rprop parameters
	double rp_dw0, rp_dw_plus, rp_dw_minus, rp_dw_min, rp_dw_max;

	ANNMLPTrainParams(TermCriteria term_crit, ANNTrainMethod train_method, double param1, double param2)
	{
		*this = *(ANNMLPTrainParams*)&(CvANN_MLP_TrainParams(*(CvTermCriteria*)&term_crit, (int)train_method, param1, param2));
	}

	ANNMLPTrainParams(TermCriteria term_crit, ANNTrainMethod train_method, double param1)
	{
		*this = *(ANNMLPTrainParams*)&(CvANN_MLP_TrainParams(*(CvTermCriteria*)&term_crit, (int)train_method, param1));
	}

	static property ANNMLPTrainParams Default
	{
		ANNMLPTrainParams get()
		{
			ANNMLPTrainParams defaultParams = *(ANNMLPTrainParams*)&(CvANN_MLP_TrainParams());
			return defaultParams;
		}
	}
};

public value struct TrainTestSplit
{
	[StructLayoutAttribute(LayoutKind::Explicit)]
	value struct TrainSamplePart
	{
		[FieldOffsetAttribute(0)]
		int count;
		[FieldOffsetAttribute(0)]
		float portion;
	};

	TrainSamplePart train_sample_part;
	MLTrainTestPartMode train_sample_part_mode;

	[StructLayoutAttribute(LayoutKind::Explicit)]
	value struct ClassPart
	{
		[FieldOffsetAttribute(0)]
		IntPtr count;
		[FieldOffsetAttribute(0)]
		IntPtr portion;
	};

	ClassPart class_part;
	MLTrainTestPartMode class_part_mode;
	bool mix;

	TrainTestSplit(int _train_sample_count, bool _mix)
	{
		*this = *(TrainTestSplit*)&(CvTrainTestSplit(_train_sample_count, mix));
	}

	TrainTestSplit(int _train_sample_count)
	{
		*this = *(TrainTestSplit*)&(CvTrainTestSplit(_train_sample_count));
	}

	TrainTestSplit(float _train_sample_portion, bool _mix)
	{
		*this = *(TrainTestSplit*)&(CvTrainTestSplit(_train_sample_portion, mix));
	}

	TrainTestSplit(float _train_sample_portion)
	{
		*this = *(TrainTestSplit*)&(CvTrainTestSplit(_train_sample_portion));
	}

	static property TrainTestSplit Default
	{
		TrainTestSplit get()
		{
			TrainTestSplit defaultParams = *(TrainTestSplit*)&(CvTrainTestSplit());
			return defaultParams;
		}
	}
};

//////////////////////////////////////////////////////////////////////////
NAMESPACE_END
//////////////////////////////////////////////////////////////////////////